package com.ld.shieldsb.canalclient.model;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import javax.annotation.PostConstruct;

import com.alibaba.otter.canal.common.utils.BooleanMutex;

/**
 * 同步开关,暂时实现一个只支持本地的，可以通过子类继承自己扩展
 *
 * @author rewerma @ 2018-10-20
 * @version 1.0.0
 */
public class SyncSwitch {
    /*本地锁*/
    private static final Map<String, BooleanMutex> LOCAL_LOCK = new ConcurrentHashMap<>();
    /* 分布式锁*/
    private static final Map<String, BooleanMutex> DISTRIBUTED_LOCK = new ConcurrentHashMap<>();

    private Mode mode = Mode.LOCAL;

    @PostConstruct
    public void init() {
        mode = Mode.LOCAL;
        LOCAL_LOCK.clear();
    }

    public void initMutex(String destination) {
        mode = Mode.LOCAL;
        LOCAL_LOCK.clear();
        // 对应每个destination注册锁
        LOCAL_LOCK.put(destination, new BooleanMutex(true));
    }

    public synchronized void refresh() {
        for (String destination : LOCAL_LOCK.keySet()) {
            BooleanMutex booleanMutex;
            if (mode == Mode.LOCAL) {
                booleanMutex = LOCAL_LOCK.get(destination);
                if (booleanMutex == null) {
                    LOCAL_LOCK.put(destination, new BooleanMutex(true));
                }
            }
        }
    }

    /**
     * 开关关闭，阻塞
     * 
     * @Title off
     * @author 吕凯
     * @date 2022年1月12日 上午11:12:18
     * @param destination
     *            void
     */
    public synchronized void off(String destination) {
        if (mode == Mode.LOCAL) {
            BooleanMutex mutex = LOCAL_LOCK.get(destination);
            if (mutex != null && mutex.state()) {
                mutex.set(false);
            }
        }
    }

    /**
     * 开关开启，唤醒阻塞线程
     * 
     * @Title on
     * @author 吕凯
     * @date 2022年1月12日 上午11:12:43
     * @param destination
     *            void
     */
    public synchronized void on(String destination) {
        if (mode == Mode.LOCAL) {
            BooleanMutex mutex = LOCAL_LOCK.get(destination);
            if (mutex != null && !mutex.state()) {
                mutex.set(true);
            }
        }
    }

    public synchronized void release(String destination) {
        if (mode == Mode.LOCAL) {
            BooleanMutex mutex = LOCAL_LOCK.get(destination);
            if (mutex != null && !mutex.state()) {
                mutex.set(true);
            }
        }
        if (mode == Mode.DISTRIBUTED) {
            BooleanMutex mutex = DISTRIBUTED_LOCK.get(destination);
            if (mutex != null && !mutex.state()) {
                mutex.set(true);
            }
        }
    }

    /**
     * 获取开关状态
     * 
     * @Title status
     * @author 吕凯
     * @date 2022年1月12日 上午11:10:09
     * @param destination
     * @return boolean
     */
    public boolean status(String destination) {
        if (mode == Mode.LOCAL) {
            BooleanMutex mutex = LOCAL_LOCK.get(destination);
            if (mutex != null) {
                return mutex.state();
            } else {
                return false;
            }
        } else {
            BooleanMutex mutex = DISTRIBUTED_LOCK.get(destination);
            if (mutex != null) {
                return mutex.state();
            } else {
                return false;
            }
        }
    }

    /**
     * 判断开关是否存在
     * 
     * @Title exists
     * @author 吕凯
     * @date 2022年1月12日 下午6:02:41
     * @param destination
     * @return boolean
     */
    public boolean exists(String destination) {
        if (mode == Mode.LOCAL) {
            BooleanMutex mutex = LOCAL_LOCK.get(destination);
            return mutex != null;
        } else {
            BooleanMutex mutex = DISTRIBUTED_LOCK.get(destination);
            return mutex != null;
        }
    }

    public void get(String destination) throws InterruptedException {
        if (mode == Mode.LOCAL) {
            BooleanMutex mutex = LOCAL_LOCK.get(destination);
            if (mutex != null) {
                mutex.get();
            }
        } else {
            BooleanMutex mutex = DISTRIBUTED_LOCK.get(destination);
            if (mutex != null) {
                mutex.get();
            }
        }
    }

    public void get(String destination, long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
        if (mode == Mode.LOCAL) {
            BooleanMutex mutex = LOCAL_LOCK.get(destination);
            if (mutex != null) {
                mutex.get(timeout, unit);
            }
        } else {
            BooleanMutex mutex = DISTRIBUTED_LOCK.get(destination);
            if (mutex != null) {
                mutex.get(timeout, unit);
            }
        }
    }

}
